package com.ruirenyun.config.filter;

import com.ruirenyun.entity.MobileUser;
import com.ruirenyun.entity.constant.RedisKey;
import com.ruirenyun.entity.constant.SYS;
import com.ruirenyun.util.common.BeanUtil;
import com.ruirenyun.util.redis.utils.RedisUtil;
import org.springframework.util.AntPathMatcher;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

/**
 * 用于检测用户是否登陆的过滤器，如果未登录，则向前端返回未登录的状态代码
 * <p/>
 * 配置参数
 * <p/>
 * checkKey 需检查的在 redis 中保存的关键字<br/>
 * notCheckURLList 不做检查的URL列表，以分号分开，并且 URL 中不包括 ContextPath<br/>
 */
public class CheckLoginFilter implements Filter {
    protected FilterConfig filterConfig = null;
    private List<String> notCheckLoginUrlList = new ArrayList<>();
    private String key = null;
    private AntPathMatcher matcher;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        servletRequest.setCharacterEncoding("UTF-8");
        servletResponse.setCharacterEncoding("UTF-8");

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        RedisUtil redisUtil = BeanUtil.getBean(RedisUtil.class);
        String originHeader = request.getHeader("Origin");
        response.setHeader("Access-Control-Allow-Origin", originHeader);
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With," +
                " Content-Type, Accept,access-control-allow-methods," +
                "AuthorityUserName," +
                "access-control-allow-origin,Pragma,Cache-Control," +
                "access-control-allow-credentials,Access-Control-Max-Age,Authority");
        if (key == null) {
            filterChain.doFilter(request, response);
            return;
        }
        if (checkRequestUrlIntNotFilterList(request)) {
            filterChain.doFilter(request, response);
            return;
        }
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            filterChain.doFilter(request, response);
        } else {
            //必须登录
            String authority = request.getHeader("Authority");
            String loginKey = key + authority;
            MobileUser user = (MobileUser) redisUtil.get(loginKey);
            if (user == null) {
                response.setHeader("Content-type", "text/plain;charset=UTF-8");
                response.getOutputStream().write(("{\"code\":\"" + SYS.L10000.name() + "\",\"msg\":\"" + SYS.L10000.getValue() + "\"}").getBytes());
                response.getOutputStream().flush();
                return;
            }
            //续签 30 分钟
            redisUtil.expire(loginKey, 1800);
            redisUtil.expire(RedisKey.USER_LOGIN_ROLE + user.getPhone(), 1800);
            filterChain.doFilter(request, response);
        }

    }

    @Override
    public void destroy() {
        notCheckLoginUrlList.clear();
    }

    private boolean checkRequestUrlIntNotFilterList(HttpServletRequest request) {
        String uri = request.getRequestURI();
        return notCheckLoginUrlList.stream().anyMatch(s -> matcher.match(s, uri));
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        matcher = new AntPathMatcher();
        matcher.setCachePatterns(true);
        this.filterConfig = filterConfig;
        key = filterConfig.getInitParameter("checkKey");
        String notCheckUrlListStr = filterConfig.getInitParameter("notCheckLoginUrlList");
        if (notCheckUrlListStr != null) {
            StringTokenizer st = new StringTokenizer(notCheckUrlListStr, ";");
            notCheckLoginUrlList.clear();
            while (st.hasMoreTokens()) {
                String s = st.nextToken();
                notCheckLoginUrlList.add(s);
            }
        }
    }
}
